Contents
  1. 1. 提取
  2. 2. 恢复符号表

download:https://service.tp-link.com.cn/detail_download_8676.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ binwalk TL-WR886N\ V6.0_2.3.8\ Build\ 190826\ Rel.54648n.bin 

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
12656 0x3170 U-Boot version string, "U-Boot 1.1.4 (May 8 2016 - 07:42:47)"
12704 0x31A0 CRC32 polynomial table, big endian
13932 0x366C uImage header, header size: 64 bytes, header CRC: 0x773178DD, created: 2016-05-08 14:42:48, image size: 20788 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0x983BDABA, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "u-boot image"
13996 0x36AC LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 52148 bytes
41472 0xA200 LZMA compressed data, properties: 0x6E, dictionary size: 8388608 bytes, uncompressed size: 2372176 bytes 📌
791104 0xC1240 LZMA compressed data, properties: 0x5A, dictionary size: 8388608 bytes, uncompressed size: 1731 bytes
792301 0xC16ED LZMA compressed data, properties: 0x5A, dictionary size: 8388608 bytes, uncompressed size: 7272 bytes
793897 0xC1D29 LZMA compressed data, properties: 0x5A, dictionary size: 8388608 bytes, uncompressed size: 200 bytes
794124 0xC1E0C LZMA compressed data, properties: 0x5A, dictionary size: 8388608 bytes, uncompressed size: 247 bytes
...
# 可以使用binwalk直接获取,解压后的文件A200就是我们下面想要一步步提取的系统文件
$ binwalk -Me TL-WR886N\ V6.0_2.3.8\ Build\ 190826\ Rel.54648n.bin

这里有U-Boot,CRC32,uImage header,在0xA200处有一个2M多的lzma压缩包

提取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# dd提取uImage镜像 skip = uImage header's start_addr | count = image size+header size
$ dd if=TL-WR886N\ V6.0_2.3.8\ Build\ 190826\ Rel.54648n.bin of=uboot.img bs=1 skip=13932 count=749632

$ binwalk uboot.img

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x773178DD, created: 2016-05-08 14:42:48, image size: 20788 bytes, Data Address: 0x80010000, Entry Point: 0x80010000, data CRC: 0x983BDABA, OS: Linux, CPU: MIPS, image type: Firmware Image, compression type: lzma, image name: "u-boot image"
64 0x40 LZMA compressed data, properties: 0x5D, dictionary size: 8388608 bytes, uncompressed size: 52148 bytes
27540 0x6B94 LZMA compressed data, properties: 0x6E, dictionary size: 8388608 bytes, uncompressed size: 2372176 bytes


# dd解压镜像lzma数据
$ dd if=uboot.img of=uboot.lzma bs=1 skip=64
???
暂不分析

对于2M大小的lzma压缩包,可能会有我们想要的信息,提取出来

1
2
3
4
5
6
# skip = start_addr | count = next_start_addr - start_addr = 791104-41472
$ dd if=TL-WR886N\ V6.0_2.3.8\ Build\ 190826\ Rel.54648n.bin of=A200.lzma bs=1 skip=41472 count=749632

# 解压
$ lzma -d A200.lzma
lzma: A200.lzma: Compressed data is corrupt

使用winhex查看bin文件

在0xA200的结尾0xC1240上下都有数据存在,而上方的FF FF更像是文件结束的位置

再看到0xA200处,前面都是00 00,很明显的结束

所以找到0xA200真正的结束位置是在0xC0F1A,即count = 0xC0F1B - 0xA200 = 748827

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 $ dd if=TL-WR886N\ V6.0_2.3.8\ Build\ 190826\ Rel.54648n.bin of=A200.lzma bs=1 skip=41472 count=748827  
$ lzma -d A200.lzma

# 查看解压后的文件A200,应该就是我们想要的系统文件
$ binwalk A200

DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
1851668 0x1C4114 Certificate in DER format (x509 v3), header length: 4, sequence length: 4
1858956 0x1C5D8C Certificate in DER format (x509 v3), header length: 4, sequence length: 4
1904512 0x1D0F80 VxWorks operating system version "5.5.1" , compiled: "Aug 26 2019, 15:10:48"
1973916 0x1E1E9C Copyright string: "Copyright(C) 2001-2011 by TP-LINK TECHNOLOGIES CO., LTD."
2003596 0x1E928C VxWorks WIND kernel version "2.6"
2048864 0x1F4360 HTML document header
2048929 0x1F43A1 HTML document footer
2069052 0x1F923C PEM certificate
2069108 0x1F9274 PEM RSA private key
2078560 0x1FB760 Base64 standard index table
2087437 0x1FDA0D StuffIt Deluxe Segment (data): f
2113876 0x204154 CRC32 polynomial table, big endian
2114900 0x204554 CRC32 polynomial table, big endian
2115924 0x204954 CRC32 polynomial table, big endian
2116948 0x204D54 CRC32 polynomial table, big endian
2137292 0x209CCC XML document, version: "1.0"
2156884 0x20E954 SHA256 hash constants, big endian
2254945 0x226861 StuffIt Deluxe Segment (data): f
2254976 0x226880 StuffIt Deluxe Segment (data): fError

恢复符号表

导入ida进行分析(设置为MIPS big endian),和上次遇到的情况一样,还是什么都分析不出来。需要确定加载基址。

前面在使用binwalk查看bin文件时,在uboot imgae header中有Data Address: 0x80010000, Entry Point: 0x80010000,但是这应该只是uboot的加载基址。

在0xa200前也发现了疑似header数据段指向了0x80001000,而这个地址也正是许多固件文件的加载地址。尝试使用该地址作为加载地址

依旧还是什么都没有,不过通过在一些地址按”C”,可以自动分析出函数,最终解析出了两千多个函数,依旧没有符号表信息,且通过分析该文件,并没有找到符号表相关。在通过binwalk解压出的文件中查找bzero函数

1
2
3
4
5
6
7
$ grep -r bzero ./
Binary file ./C2E58 matches

# _TL-WR886N V6.0_2.3.8 Build 190826 Rel.54648n.bin.extracted中只有三个binary文件
36AC uboot文件
A200 固件系统
C2E58 符号文件

查看C2E58文件,可以找出符号索引的规律,同时符号表中的符号之间用\x00分隔

利用idapython修复符号表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import idautils
import idc
import idaapi

symfile_path = 'C:\\C2E58'

# 符号起始
symbols_table_start = 8
# 字符串起始
strings_table_start = 0x9d80

with open(symfile_path, 'rb') as f:
symfile_contents = f.read()

symbols_table = symfile_contents[symbols_table_start:strings_table_start]
strings_table = symfile_contents[strings_table_start:]

def get_strings_by_offset(offset):
index = 0
while True:
if strings_table[offset+index] != 0:
index += 1
else:
break
return strings_table[offset:offset+index]

def get_symbols_metadata():
symbols = []
for offset in range(0, len(symbols_table), 8):
# 一个符号的段落
symbol_item = symbols_table[offset:offset+8]
# 标志位
flag = symbol_item[0]
print(flag)
# 符号偏移
string_offset = int(symbol_item[1:4].hex(), 16)
print(string_offset)
# 根据符号偏移找到符号名
string_name = get_strings_by_offset(string_offset).decode("utf-8")
print(string_name)
# 符号在文件内存中的地址
target_address = int(symbol_item[4:].hex(), 16)
print(target_address)
# 列表
symbols.append((flag, string_name, target_address))
return symbols

def add_symbols(symbols_meta_data):
# 对于列表symbols_meta_data中的数据
for flag, string_name, target_address in symbols_meta_data:
# 对目标地址进行重命名
idc.set_name(target_address, str(string_name))
if flag == '\x54':
# 指定地址 字节转化为指令
idc.MakeCode(target_address)
# 指定地址转换成函数
idc.MakeFunction(target_address)

if __name__ == "__main__":
symbols_metadata = get_symbols_metadata()
add_symbols(symbols_metadata)

也可以直接通过\x00进行字符串截断symbol_strings = strings_table.split(chr(0)),直接挨个儿放到target_address去…个人感觉不如根据偏移找到符号名再放精准..

仍有部分未被修复

Reference:

https://www.secpulse.com/archives/75635.html

https://cq674350529.github.io/2018/09/19/TP-Link-wr886v6-%E5%9B%BA%E4%BB%B6%E8%A7%A3%E6%9E%90/